package edu.tgc.web.controller.file;

import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Collection;

import org.abyss.common.Constants;
import org.abyss.common.exception.ServiceException;
import org.abyss.common.web.controller.CommonCrudController.createValidate;
import org.abyss.common.web.controller.CommonCrudController.updateValidate;
import org.abyss.common.web.controller.easyui.CommonCrudEasyUiController;
import org.abyss.common.web.controller.easyui.EasyuiAjaxFormResult;
import org.abyss.upload.resolver.DefaultUploadResolverFactory;
import org.abyss.upload.resolver.UploadResolverFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import edu.tgc.entity.file.AbstractFileResource;
import edu.tgc.entity.file.FilePath;
import edu.tgc.entity.system.SysUser;
import edu.tgc.web.form.file.FileResourceForm;

public abstract class AbstractFileResourceController<E extends AbstractFileResource<SysUser, ID>, ID extends Serializable, FORM extends FileResourceForm<ID>> extends CommonCrudEasyUiController<E, ID, FORM> {

    protected UploadResolverFactory uploadResolverFactory = new DefaultUploadResolverFactory();

    @Override
    protected void buildIgnoreProperties(Collection<String> createIgnoreProperties, Collection<String> updateIgnoreProperties) {
        updateIgnoreProperties.add("size");
        updateIgnoreProperties.add("path");
        updateIgnoreProperties.add("originalFilename");
        updateIgnoreProperties.add("ext");
    }

    public abstract FilePath getPath();

    @Override
    @ResponseBody
    @RequestMapping(value = Constants.Path.CREATE, method = RequestMethod.POST)
    public EasyuiAjaxFormResult create(@Validated(value = createValidate.class) FORM form, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {
        if (bindingResult.hasErrors()) {
            return buildCreateErrorResult(form, bindingResult.getFieldError().getDefaultMessage());
        } else {
            try {
                E entity = buildCreateEntity(form);
                MultipartFile file = form.getFile();
                if (file != null) {
                    entity.setContentType(file.getContentType());
                    entity.setSize(file.getSize());
                    entity.setPath(getPath());
                    String originalFilename = file.getOriginalFilename();
                    entity.setOriginalFilename(originalFilename);
                    int lastIndexOf = originalFilename.lastIndexOf(".");
                    String name = originalFilename;
                    if (lastIndexOf != -1) {
                        entity.setExt(originalFilename.substring(lastIndexOf + 1));
                        name = originalFilename.substring(0, lastIndexOf);
                    }
                    if (entity.getName() == null) {
                        entity.setName(name);
                    }
                }
                entity = this.baseService.create(entity, this.createIgnoreProperties);
                if (file != null) {
                    this.uploadResolverFactory.build(getPath()).write(file, entity.getId().toString(), getPath());
                }
                return buildCreateSuccessResult(form, entity);
            } catch (ServiceException | IllegalStateException | IOException e) {
                return buildCreateErrorResult(form, e.getMessage());
            }
        }
    }

    @Override
    @ResponseBody
    @RequestMapping(value = Constants.Path.UPDATE, method = RequestMethod.POST)
    public EasyuiAjaxFormResult update(@Validated(value = updateValidate.class) FORM form, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {
        if (bindingResult.hasErrors()) {
            return buildUpdateErrorResult(form, bindingResult.getFieldError().getDefaultMessage());
        } else {
            try {
                E entity = buildUpdateEntity(form);
                MultipartFile file = form.getFile();
                if (file != null) {
                    entity.setContentType(file.getContentType());
                    entity.setSize(file.getSize());
                    entity.setPath(getPath());
                    String originalFilename = file.getOriginalFilename();
                    entity.setOriginalFilename(originalFilename);
                    int lastIndexOf = originalFilename.lastIndexOf(".");
                    String name = originalFilename;
                    if (lastIndexOf != -1) {
                        entity.setExt(originalFilename.substring(lastIndexOf + 1));
                        name = originalFilename.substring(0, lastIndexOf);
                    }
                    if (entity.getName() == null) {
                        entity.setName(name);
                    }
                    entity = this.baseService.update(entity, this.createIgnoreProperties);
                    this.uploadResolverFactory.build(getPath()).write(file, entity.getId().toString(), getPath());
                } else {
                    entity = this.baseService.update(entity, this.updateIgnoreProperties);
                }
                return buildUpdateSuccessResult(form, entity);
            } catch (ServiceException | IllegalStateException | IOException e) {
                return buildUpdateErrorResult(form, e.getMessage());
            }
        }
    }

    @Override
    @ResponseBody
    @RequestMapping(value = Constants.Path.DELETE)
    public EasyuiAjaxFormResult delete(FORM form, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {
        if (bindingResult.hasErrors()) {
            return buildDeleteErrorResult(form, bindingResult.getFieldError().getDefaultMessage());
        } else {
            try {
                E entity = this.baseService.delete(form.getId());
                this.uploadResolverFactory.build(getPath()).delete(form.getId().toString(), getPath());
                return buildDeleteSuccessResult(form, entity);
            } catch (ServiceException | IOException e) {
                return buildDeleteErrorResult(form, e.getMessage());
            }
        }
    }

    @RequestMapping(value = "/download")
    @ResponseBody
    public ResponseEntity<byte[]> downloadFile(FORM form, ModelMap modelMap) {
        ID id = form.getId();
        E entity = this.baseService.getById(id);
        if (entity != null) {
            byte[] buffers;
            try {
                buffers = this.uploadResolverFactory.build(getPath()).read(id.toString(), getPath());
                String fileName = entity.getName() + (entity.getExt() == null ? "" : "." + entity.getExt());
                try {
                    fileName = new String(fileName.getBytes("gb2312"), "ISO8859-1");
                } catch (UnsupportedEncodingException e) {
                }
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                headers.setContentDispositionFormData("attachment", fileName);
                return new ResponseEntity<>(buffers, headers, HttpStatus.OK);
            } catch (IOException e) {
            }
        }
        return null;
    }

}
